import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart' as dio;
import 'package:get/get.dart';
import 'package:signage/app/routes/app_pages.dart';
import 'package:signage/app/utils/sp_util.dart';
import 'package:signage/app/utils/toast_utils.dart';

class HttpClient {
  static final HttpClient _instance = HttpClient._internal();
  late final dio.Dio _dio;

  // 基础 URL
  static const String baseUrl = 'http://test.i-work.tech/qspace-api';

  factory HttpClient() {
    return _instance;
  }

  HttpClient._internal() {
    final dio.BaseOptions options = dio.BaseOptions(
      baseUrl: baseUrl,
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
      headers: {
        'Content-Type': 'application/json',
      },
    );

    _dio = dio.Dio(options);

    _dio.interceptors.add(dio.LogInterceptor(
      request: true,
      requestHeader: true,
      requestBody: true,
      responseHeader: true,
      responseBody: true,
      error: true,
      logPrint: (object) {
        print('Dio Log: $object');
      },
    ));

    _dio.interceptors.add(dio.InterceptorsWrapper(
      onRequest: (options, handler) async {
        final token = SpUtil.getString('token');
        if (token != null) {
          options.headers['Authorization'] = 'Bearer $token';
        }
        print('Request: ${options.method} ${options.uri}');
        return handler.next(options);
      },
      onResponse: (response, handler) {
        print(
            'Response: ${response.statusCode} ${response.requestOptions.uri}');
        return handler.next(response);
      },
      onError: (error, handler) {
        print('Error: ${error.message}');
        return handler.next(error);
      },
    ));
  }

  Future<LoginResponse> register({
    required String mobile,
    required String captcha,
  }) async {
    try {
      final response = await _dio.post(
        '/api/org/user/reg/mobile',
        data: {
          'mobile': mobile,
          'captcha': captcha,
        },
      );
      return LoginResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<LoginResponse> login({
    required String mobile,
    required String captcha,
  }) async {
    try {
      final response = await _dio.post(
        '/api/login/mobile',
        data: {
          'mobile': mobile,
          'captcha': captcha,
        },
      );
      return LoginResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<LoginResponse> changeMobile({
    required String mobile,
    required String captcha,
  }) async {
    try {
      final response = await _dio.post(
        '/api/org/user/mobile',
        data: {
          'mobile': mobile,
          'captcha': captcha,
        },
      );
      return LoginResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<CaptchaResponse> getCaptcha({
    required String mobile,
  }) async {
    try {
      final response = await _dio.post(
        '/api/org/user/reg/mobile/captcha',
        data: {
          'mobile': mobile,
          't': DateTime.now().millisecondsSinceEpoch,
        },
      );
      final captchaResponse = CaptchaResponse.fromJson(response.data);
      if (captchaResponse.code == 200) {
        return captchaResponse;
      } else {
        throw Exception(captchaResponse.msg);
      }
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<CaptchaResponse> getCaptcha3({
    required String mobile,
  }) async {
    try {
      final response = await _dio.post(
        '/api/org/user/login/mobile/captcha',
        data: {
          'mobile': mobile,
          't': DateTime.now().millisecondsSinceEpoch,
        },
      );
      final captchaResponse = CaptchaResponse.fromJson(response.data);
      if (captchaResponse.code == 200) {
        return captchaResponse;
      } else {
        throw Exception(captchaResponse.msg);
      }
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<CaptchaResponse> getCaptcha2({
    required String mobile,
  }) async {
    try {
      final response = await _dio.post(
        '/api/org/user/update/mobile/captcha',
        data: {
          'mobile': mobile,
          't': DateTime.now().millisecondsSinceEpoch,
        },
      );
      final captchaResponse = CaptchaResponse.fromJson(response.data);
      if (captchaResponse.code == 200) {
        return captchaResponse;
      } else {
        ToastUtils.show(captchaResponse.msg ?? '获取验证码失败');
        throw Exception(captchaResponse.msg);
      }
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<UserInfoResponse> getUserInfo() async {
    try {
      final response = await _dio.get('/api/org/user');
      final responseData = response.data;
      
      // Check if response data is already a Map
      final responseMap = responseData is Map<String, dynamic> 
          ? responseData 
          : jsonDecode(responseData);

      if (responseMap['code'] == 401) {
        // 清除token
        SpUtil.clearStoredUid();
        SpUtil.remove('token');
        // 跳转登录页面
        Get.offAllNamed(Routes.LOGIN);
      }
      return UserInfoResponse.fromJson(responseMap);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<BaseResponse> logout() async {
    try {
      final response = await _dio.post('/api/logout');
      return BaseResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<RouterResponse> getRouters() async {
    try {
      final response = await _dio.get('/api/getRouters');
      return RouterResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 文件管理相关接口
  // 文件上传
  Future<FileResponse> uploadFile({
    required File file,
  }) async {
    try {
      String fileName = file.path.split('/').last;
      dio.FormData formData = dio.FormData.fromMap({
        'file': await dio.MultipartFile.fromFile(
          file.path,
          filename: fileName,
        ),
      });

      final response = await _dio.post(
        '/api/base/file',
        data: formData,
      );
      return FileResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 读取文件信息
  Future<FileInfoResponse> getFileInfo({
    required String fileId,
  }) async {
    try {
      final response = await _dio.get(
        '/api/base/file/info/$fileId',
      );
      return FileInfoResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 下载文件
  Future<void> downloadFile({
    required String fileId,
    required String savePath,
    dio.ProgressCallback? onReceiveProgress,
  }) async {
    try {
      await _dio.download(
        '/api/base/file/download/$fileId',
        savePath,
        onReceiveProgress: onReceiveProgress,
      );
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 物联网相关接口
  // 获取设备列表
  Future<DeviceListResponse> getDeviceList({
    int page = 1,
    int pageSize = 10,
  }) async {
    try {
      final response = await _dio.get(
        '/api/iot/devices',
        queryParameters: {
          'page': page,
          'pageSize': pageSize,
        },
      );
      return DeviceListResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 获取设备详情
  Future<DeviceDetailResponse> getDeviceDetail({
    required String deviceId,
  }) async {
    try {
      final response = await _dio.get('/api/iot/device/$deviceId');
      return DeviceDetailResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 控制设备
  Future<BaseResponse> controlDevice({
    required String deviceId,
    required Map<String, dynamic> command,
  }) async {
    try {
      final response = await _dio.post(
        '/api/iot/device/$deviceId/control',
        data: command,
      );
      return BaseResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 墨水牌相关接口
  // 获取字体列表
  Future<FontListResponse> getFontList() async {
    try {
      final response = await _dio.get('/eink/font');
      return FontListResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 获取蓝牙固件
  Future<FirmwareResponse> getBluetoothFirmware(String board) async {
    try {
      final response = await _dio.post('/eink/blfirm/query', data: {
        'board': board,
      });
      return FirmwareResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 上传蓝牙固件
  Future<BaseResponse> uploadBluetoothFirmware({
    required File firmwareFile,
  }) async {
    try {
      String fileName = firmwareFile.path.split('/').last;
      dio.FormData formData = dio.FormData.fromMap({
        'file': await dio.MultipartFile.fromFile(
          firmwareFile.path,
          filename: fileName,
        ),
      });

      final response = await _dio.post(
        '/eink/blfirm',
        data: formData,
      );
      return BaseResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 更新用户头像
  Future<BaseResponse> updateAvatar({
    required String avatarUrl,
  }) async {
    try {
      final response = await _dio.post(
        '/api/org/user/avatar',
        data: {
          'avatar': avatarUrl,
        },
      );
      return BaseResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 更新用户显示名称
  Future<BaseResponse> updateDisplayName({
    required String name,
  }) async {
    try {
      final response = await _dio.post(
        '/api/org/user/name',
        data: {
          'name': name,
        },
      );
      return BaseResponse.fromJson(response.data);
    } on dio.DioException catch (e) {
      throw _handleError(e);
    }
  }

  Exception _handleError(dio.DioException error) {
    switch (error.type) {
      case dio.DioExceptionType.connectionTimeout:
        return Exception('连接超时');
      case dio.DioExceptionType.receiveTimeout:
        return Exception('接收超时');
      case dio.DioExceptionType.sendTimeout:
        return Exception('发送超时');
      case dio.DioExceptionType.badResponse:
        final statusCode = error.response?.statusCode;
        final responseData = error.response?.data;
        if (statusCode == 401) {
          return UnauthorizedException(responseData?['msg'] ?? '未授权');
        }
        return Exception(responseData?['msg'] ?? '请求失败');
      default:
        return Exception(error.message ?? '未知错误');
    }
  }
}

class BaseResponse {
  final dynamic data;
  final int code;
  final String? msg;

  BaseResponse({
    this.data,
    required this.code,
    this.msg,
  });

  factory BaseResponse.fromJson(Map<String, dynamic> json) {
    return BaseResponse(
      data: json['data'],
      code: json['code'] as int,
      msg: json['msg'] as String?,
    );
  }
}

class LoginResponse extends BaseResponse {
  final String? token;
  final String? id;

  LoginResponse({
    this.token,
    this.id,
    required int code,
    String? msg,
  }) : super(code: code, msg: msg, data: token);

  factory LoginResponse.fromJson(Map<String, dynamic> json) {
    return LoginResponse(
      token: json['data'] as String?,
      id: json['id'].toString(),
      code: json['code'] as int,
      msg: json['msg'] as String?,
    );
  }
}

class CaptchaResponse extends BaseResponse {
  final String? img;
  final String? uuid;

  CaptchaResponse({
    this.img,
    this.uuid,
    required int code,
    String? msg,
  }) : super(code: code, msg: msg);

  factory CaptchaResponse.fromJson(Map<String, dynamic> json) {
    final data = json['data'] as Map<String, dynamic>?;
    return CaptchaResponse(
      img: data?['img'] as String?,
      uuid: data?['uuid'] as String?,
      code: json['code'] as int,
      msg: json['msg'] as String?,
    );
  }
}

class UserInfoResponse extends BaseResponse {
  final UserInfo? userInfo;

  UserInfoResponse({
    this.userInfo,
    required int code,
    String? msg,
  }) : super(code: code, msg: msg);

  factory UserInfoResponse.fromJson(Map<String, dynamic> json) {
    return UserInfoResponse(
      userInfo: json['data'] != null ? UserInfo.fromJson(json['data']) : null,
      code: json['code'] as int,
      msg: json['msg'] as String?,
    );
  }
}

class RouterResponse extends BaseResponse {
  final List<Router>? routers;

  RouterResponse({
    this.routers,
    required int code,
    String? msg,
  }) : super(code: code, msg: msg);

  factory RouterResponse.fromJson(Map<String, dynamic> json) {
    final List<dynamic>? routerList = json['data'] as List<dynamic>?;
    return RouterResponse(
      routers: routerList?.map((e) => Router.fromJson(e)).toList(),
      code: json['code'] as int,
      msg: json['msg'] as String?,
    );
  }
}

class UserInfo {
  final String? name;
  final String? accountName;
  final String? avatar;
  final String? mobile;

  UserInfo({
    this.name,
    this.accountName,
    this.avatar,
    this.mobile,
  });

  factory UserInfo.fromJson(Map<String, dynamic> json) {
    return UserInfo(
      name: json['name'] as String?,
      accountName: json['accountName'] as String?,
      avatar: json['avatar'] as String?,
      mobile: json['mobile'] as String?,
    );
  }
}

class Router {
  final String? name;
  final String? path;
  final String? component;
  final List<Router>? children;

  Router({
    this.name,
    this.path,
    this.component,
    this.children,
  });

  factory Router.fromJson(Map<String, dynamic> json) {
    return Router(
      name: json['name'] as String?,
      path: json['path'] as String?,
      component: json['component'] as String?,
      children: (json['children'] as List<dynamic>?)
          ?.map((e) => Router.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }
}

class UnauthorizedException implements Exception {
  final String message;
  UnauthorizedException(this.message);
}

class FileResponse extends BaseResponse {
  final FileInfo? fileInfo;

  FileResponse({
    this.fileInfo,
    required String msg,
    required int code,
    required bool success,
  }) : super(msg: msg, code: code, data: fileInfo);

  factory FileResponse.fromJson(Map<String, dynamic> json) {
    return FileResponse(
      fileInfo: json['data'] != null ? FileInfo.fromJson(json['data']) : null,
      msg: json['msg'] as String,
      code: json['code'] as int,
      success: json['success'] as bool,
    );
  }
}

class FileInfoResponse extends BaseResponse {
  final FileInfo? fileInfo;

  FileInfoResponse({
    this.fileInfo,
    required String msg,
    required int code,
  }) : super(msg: msg, code: code, data: fileInfo);

  factory FileInfoResponse.fromJson(Map<String, dynamic> json) {
    return FileInfoResponse(
      fileInfo: json['data'] != null ? FileInfo.fromJson(json['data']) : null,
      msg: json['msg'] as String,
      code: json['code'] as int,
    );
  }
}

class DeviceListResponse extends BaseResponse {
  final List<Device>? devices;
  final int total;
  final int page;
  final int pageSize;

  DeviceListResponse({
    this.devices,
    required this.total,
    required this.page,
    required this.pageSize,
    required String msg,
    required int code,
  }) : super(msg: msg, code: code, data: devices);

  factory DeviceListResponse.fromJson(Map<String, dynamic> json) {
    final data = json['data'] as Map<String, dynamic>?;
    return DeviceListResponse(
      devices: (data?['list'] as List<dynamic>?)
          ?.map((e) => Device.fromJson(e as Map<String, dynamic>))
          .toList(),
      total: data?['total'] as int? ?? 0,
      page: data?['page'] as int? ?? 1,
      pageSize: data?['pageSize'] as int? ?? 10,
      msg: json['msg'] as String,
      code: json['code'] as int,
    );
  }
}

class DeviceDetailResponse extends BaseResponse {
  final Device? device;

  DeviceDetailResponse({
    this.device,
    required String msg,
    required int code,
  }) : super(msg: msg, code: code, data: device);

  factory DeviceDetailResponse.fromJson(Map<String, dynamic> json) {
    return DeviceDetailResponse(
      device: json['data'] != null ? Device.fromJson(json['data']) : null,
      msg: json['msg'] as String,
      code: json['code'] as int,
    );
  }
}

class FileInfo {
  final String id;

  FileInfo({
    required this.id,
  });

  factory FileInfo.fromJson(Map<String, dynamic> json) {
    return FileInfo(
      id: json['id'] as String,
    );
  }
}

class Device {
  final String id;
  final String name;
  final String type;
  final String status;
  final Map<String, dynamic>? properties;

  Device({
    required this.id,
    required this.name,
    required this.type,
    required this.status,
    this.properties,
  });

  factory Device.fromJson(Map<String, dynamic> json) {
    return Device(
      id: json['id'] as String,
      name: json['name'] as String,
      type: json['type'] as String,
      status: json['status'] as String,
      properties: json['properties'] as Map<String, dynamic>?,
    );
  }
}

class FontListResponse extends BaseResponse {
  final List<FontInfo>? fonts;

  FontListResponse({
    this.fonts,
    required String msg,
    required int code,
  }) : super(msg: msg, code: code, data: fonts);

  factory FontListResponse.fromJson(Map<String, dynamic> json) {
    final List<dynamic>? fontList = json['data'] as List<dynamic>?;
    return FontListResponse(
      fonts: fontList?.map((e) => FontInfo.fromJson(e)).toList(),
      msg: json['msg'] as String,
      code: json['code'] as int,
    );
  }
}

class FirmwareResponse extends BaseResponse {
  final FirmwareInfo? firmware;

  FirmwareResponse({
    this.firmware,
    required String msg,
    required int code,
  }) : super(msg: msg, code: code, data: firmware);

  factory FirmwareResponse.fromJson(Map<String, dynamic> json) {
    return FirmwareResponse(
      firmware:
          json['data'] != null ? FirmwareInfo.fromJson(json['data']) : null,
      msg: json['msg'] as String,
      code: json['code'] as int,
    );
  }
}

class FontInfo {
  final String id;
  final String? pinyin;
  final String? createBy;
  final String createTime;
  final String? updateBy;
  final String? updateTime;
  final String? removeBy;
  final String? removeTime;
  final int deleted;
  final String? version;
  final String? remark;
  final String fontName;
  final String url;

  FontInfo({
    required this.id,
    this.pinyin,
    this.createBy,
    required this.createTime,
    this.updateBy,
    this.updateTime,
    this.removeBy,
    this.removeTime,
    required this.deleted,
    this.version,
    this.remark,
    required this.fontName,
    required this.url,
  });

  factory FontInfo.fromJson(Map<String, dynamic> json) {
    return FontInfo(
      id: json['id'] as String,
      pinyin: json['pinyin'] as String?,
      createBy: json['createBy'] as String?,
      createTime: json['createTime'] as String,
      updateBy: json['updateBy'] as String?,
      updateTime: json['updateTime'] as String?,
      removeBy: json['removeBy'] as String?,
      removeTime: json['removeTime'] as String?,
      deleted: json['deleted'] as int,
      version: json['version'] as String?,
      remark: json['remark'] as String?,
      fontName: json['fontName'] as String,
      url: json['url'] as String,
    );
  }
}

class FirmwareInfo {
  final String version;
  final String url;
  final String md5;
  final String description;

  FirmwareInfo({
    required this.version,
    required this.url,
    required this.md5,
    required this.description,
  });

  factory FirmwareInfo.fromJson(Map<String, dynamic> json) {
    return FirmwareInfo(
      version: json['version_MCUBOOT'].toString(),
      url: json['url'].toString(),
      md5: json['md5_MCUBOOT'].toString(),
      description: json['description'].toString(),
    );
  }
}
